package com.kim.authorization.server.config;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kim.common.utilcom.model.Result;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 授权返回结果封装Filter
 *
 * <p>
 * 考虑了很久最后还是不用这个过滤器了吧
 * 可能Oauth2.0本身不希望我们这么做
 * 如果这样做需要做很多判断，而且对于单点登录等功能更加有难度
 * 后续会改为认证服务授权成功返回token 失败返回异常类型
 * 调用认证服务的上游自行封装结构
 * PS： 后续可能还会启用！或者只需要密码登录的可以继续使用
 * </p>
 */
@Slf4j
@Deprecated
public class TokenHandleFilter implements Filter {

    /**
     * 是否存在token(授权接口并且授权成功)
     */
    private static final String ACCESS_TOKEN = "access_token";


    /**
     * 对象通用转换
     */
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void init(FilterConfig filterConfig) {
        //获取 filterRegistrationBean.addInitParameter("name","hahahhhaa")设置的参数
        log.info("TokenHandleFilter init  -> {}", filterConfig.getInitParameter("init"));
    }

    /**
     * 响应结果进行统一封装
     * <p>
     * 对 /oauth/token 接口进行响应结果进行统一封装
     * 如果授权过程出现异常则直接返回具体错误
     * 如果授权正常返回Result封装过的token对象
     * </p>
     *
     * @param servletRequest  请求体
     * @param servletResponse 响应体
     * @param filterChain     过滤器链
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("TokenHandleFilter doFilter");
        ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
        filterChain.doFilter(servletRequest, responseWrapper);
        // 获取返回JSON
        String responseContent = new String(responseWrapper.getDataStream());
        JSONObject jsonObject = JSONObject.parseObject(responseContent);
        Result result;
        if (!jsonObject.containsKey(ACCESS_TOKEN)) {
            result = jsonObject.toJavaObject(Result.class);
        } else {
            result = Result.succeed(jsonObject);
        }
        log.info("授权返回结果 -> {}", result);
        byte[] responseToSend = restResponseBytes(result);
        servletResponse.getOutputStream().write(responseToSend);
    }

    /**
     * 响应结果转为字节数组
     *
     * @param result 响应结果
     * @return byte[]
     */
    private byte[] restResponseBytes(Result result) throws IOException {
        String serialized = objectMapper.writeValueAsString(result);
        return serialized.getBytes(StandardCharsets.UTF_8);
    }

    @Override
    public void destroy() {
        log.info("TokenHandleFilter destroy");
    }


    /**
     * 自定义输出流
     */
    static class MyServletOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream ostream;

        MyServletOutputStream(ByteArrayOutputStream ostream) {
            this.ostream = ostream;
        }

        @Override
        public void write(int b) {
            // 将数据写到 stream　中
            ostream.write(b);
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {

        }
    }

    /**
     * 自定义响应包装器
     */
    static class ResponseWrapper extends HttpServletResponseWrapper {

        ByteArrayOutputStream output = new ByteArrayOutputStream();

        ResponseWrapper(HttpServletResponse response) {
            super(response);
        }

        /**
         * 将ServletOutputStream放到公共变量，解决不能多次读写问题
         * @return javax.servlet.ServletOutputStream
         */
        @Override
        public ServletOutputStream getOutputStream() {
            return new MyServletOutputStream(output);
        }

        /**
         * 获取字节数组
         * @return byte[]
         */
        byte[] getDataStream() {
            return output.toByteArray();
        }
    }
}
